"""
异步基础数据访问对象
"""
from typing import TypeVar, Generic, Type, Optional, List, Any, Dict
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func

from app.databases.database import Base

ModelType = TypeVar("ModelType", bound=Base)


class AsyncBaseRepository(Generic[ModelType]):
    """异步基础Repository类，提供通用CRUD操作"""
    
    def __init__(self, model: Type[ModelType], db: AsyncSession):
        self.model = model
        self.db = db
    
    async def get(self, id: Any) -> Optional[ModelType]:
        """根据ID获取单个记录"""
        result = await self.db.execute(
            select(self.model).where(self.model.id == id)
        )
        return result.scalar_one_or_none()
    
    async def get_multi(
        self, 
        skip: int = 0, 
        limit: int = 100,
        filters: Optional[Dict[str, Any]] = None,
        order_by: Optional[str] = None,
        desc_order: bool = False
    ) -> List[ModelType]:
        """获取多条记录"""
        query = select(self.model)
        
        if filters:
            for key, value in filters.items():
                if hasattr(self.model, key):
                    query = query.where(getattr(self.model, key) == value)
        
        # 排序
        if order_by and hasattr(self.model, order_by):
            order_column = getattr(self.model, order_by)
            if desc_order:
                query = query.order_by(order_column.desc())
            else:
                query = query.order_by(order_column)
        
        query = query.offset(skip).limit(limit)
        result = await self.db.execute(query)
        return result.scalars().all()
    
    async def create(self, obj_in: Dict[str, Any]) -> ModelType:
        """创建新记录"""
        db_obj = self.model(**obj_in)
        self.db.add(db_obj)
        await self.db.commit()
        await self.db.refresh(db_obj)
        return db_obj
    
    async def update(self, db_obj: ModelType, obj_in: Dict[str, Any]) -> ModelType:
        """更新记录"""
        for field, value in obj_in.items():
            if hasattr(db_obj, field) and value is not None:
                setattr(db_obj, field, value)
        
        await self.db.commit()
        await self.db.refresh(db_obj)
        return db_obj
    
    async def delete(self, id: Any) -> Optional[ModelType]:
        """删除记录"""
        result = await self.db.execute(
            select(self.model).where(self.model.id == id)
        )
        obj = result.scalar_one_or_none()
        
        if obj:
            await self.db.delete(obj)
            await self.db.commit()
        return obj
    
    async def count(self, filters: Optional[Dict[str, Any]] = None) -> int:
        """统计记录数量"""
        query = select(func.count(self.model.id))
        
        if filters:
            for key, value in filters.items():
                if hasattr(self.model, key):
                    query = query.where(getattr(self.model, key) == value)
        
        result = await self.db.execute(query)
        return result.scalar()
    
    async def exists(self, id: Any) -> bool:
        """检查记录是否存在"""
        result = await self.db.execute(
            select(func.count(self.model.id)).where(self.model.id == id)
        )
        return result.scalar() > 0
    
    async def get_by_field(self, field_name: str, value: Any) -> Optional[ModelType]:
        """根据字段值获取记录"""
        if not hasattr(self.model, field_name):
            raise AttributeError(f"Model {self.model.__name__} has no field {field_name}")
        
        result = await self.db.execute(
            select(self.model).where(getattr(self.model, field_name) == value)
        )
        return result.scalar_one_or_none()
    
    async def get_multi_by_field(
        self, 
        field_name: str, 
        value: Any,
        skip: int = 0,
        limit: int = 100,
        order_by: Optional[str] = None,
        desc_order: bool = False
    ) -> List[ModelType]:
        """根据字段值获取多条记录"""
        if not hasattr(self.model, field_name):
            raise AttributeError(f"Model {self.model.__name__} has no field {field_name}")
        
        query = select(self.model).where(
            getattr(self.model, field_name) == value
        ).offset(skip).limit(limit)
        
        # 排序
        if order_by and hasattr(self.model, order_by):
            order_column = getattr(self.model, order_by)
            if desc_order:
                query = query.order_by(order_column.desc())
            else:
                query = query.order_by(order_column)
        
        result = await self.db.execute(query)
        return result.scalars().all()
    
    async def update_by_field(
        self, 
        field_name: str, 
        field_value: Any, 
        update_data: Dict[str, Any]
    ) -> Optional[ModelType]:
        """根据字段值更新记录"""
        if not hasattr(self.model, field_name):
            raise AttributeError(f"Model {self.model.__name__} has no field {field_name}")
        
        obj = await self.get_by_field(field_name, field_value)
        if obj:
            return await self.update(obj, update_data)
        return None
